#include "gofgame/jumpdown/io/JumpDownController.h"

#include "string.h"
#include "stdio.h"
#include <cocos-ext.h>
#include "gofgame/jumpdown/Configuration.h"
#include "gofgame/jumpdown/util/HttpUtil.h"
#include "gofgame/common/Ref.h"
#include "gofgame/common/IllegalStateException.h"

using namespace cocos2d::extension;
using namespace gofgame::common;
using namespace gofgame::jumpdown::io;
using namespace gofgame::jumpdown::util;

JumpDownController::JumpDownController() {
	this->disposed = false;
}

void JumpDownController::submitScore(const char *userName, int level) {
	if (this->disposed) {
		_throw(IllegalStateException, "JumpDownController has been disposed");
	}
	string url = Configuration::getConfiguration().getSubmitScoreURL(userName, level);
	Ref<CCHttpRequest> request;
	*&request = new CCHttpRequest();
	request->setUrl(url.c_str());
	request->setRequestType(CCHttpRequest::kHttpGet);
	request->setResponseCallback(this, callfuncND_selector(JumpDownController::sumitScoreCallback));
	CCHttpClient::getInstance()->send(request);
}

void JumpDownController::queryScores(int pageIndex, int pageSize) {
	if (this->disposed) {
		_throw(IllegalStateException, "JumpDownController has been disposed");
	}
	string url = Configuration::getConfiguration().getQueryScoresURL(pageIndex, pageSize, "xml");
	Ref<CCHttpRequest> request;
	*&request = new CCHttpRequest();
	request->setUrl(url.c_str());
	request->setRequestType(CCHttpRequest::kHttpGet);
	request->setResponseCallback(this, callfuncND_selector(JumpDownController::queryScoresCallback));
	CCHttpClient::getInstance()->send(request);
}

void JumpDownController::addSubmitScoreListener(function<void(int*)> listener) {
	this->sumitScoreListeners.push_back(listener);
}

void JumpDownController::addQueryScoreListener(function<void(Page<Score>*)> listener) {
	this->queryScoresListeners.push_back(listener);
}

void JumpDownController::dispose() {
	this->disposed = true;
}

void JumpDownController::sumitScoreCallback(CCNode *sender, void *data) {
	if (this->disposed) {
		return;
	}
	CCHttpResponse *response = (CCHttpResponse*)data;
	if (!response || !response->isSucceed()) {
		for (auto listener : this->sumitScoreListeners) {
			listener(nullptr);
		}
		return;
	}
	vector<char> *buffer = response->getResponseData();
	string responseData(buffer->begin(),buffer->end());
	if (responseData.length() == 0) {
		for (auto listener : this->sumitScoreListeners) {
			listener(nullptr);
		}
		return;
	}
	int rank = atoi(responseData.c_str());
	for (auto listener : this->sumitScoreListeners) {
		listener(&rank);
	}
}

void JumpDownController::queryScoresCallback(CCNode *sender, void *data) {
	if (this->disposed) {
		return;
	}
	CCHttpResponse *response = (CCHttpResponse*)data;
	if (!response || !response->isSucceed()) {
		for (auto listener : this->queryScoresListeners) {
			listener(nullptr);
		}
		return;
	}
	vector<char> *buffer = response->getResponseData();
	string responseData(buffer->begin(),buffer->end());
	if (responseData.length() == 0) {
		for (auto listener : this->queryScoresListeners) {
			listener(nullptr);
		}
		return;
	}
	CCSAXParser parser;
	SAXDelegatorImpl delegator;
	parser.setDelegator(&delegator);
	parser.parse(responseData.c_str(), responseData.length());
	Page<Score> page = delegator.buildPage();
	for (auto listener : this->queryScoresListeners) {
		listener(&page);
	}
}

void JumpDownController::SAXDelegatorImpl::startElement(void *ctx, const char *name, const char **atts) {
	if (strcmp(name, "scores") == 0) {
		this->scores.clear();
		this->pageIndex = 0;
		this->pageSize = 0;
		this->totalRowCount = 0;
		for (int i = 0; atts[i]; i += 2) {
			if (strcmp(atts[i], "expectedPageIndex") == 0) {
				this->pageIndex = atoi(atts[i + 1]);
			} else if (strcmp(atts[i], "pageSize") == 0) {
				this->pageSize = atoi(atts[i + 1]);
			} else if (strcmp(atts[i], "totalRowCount") == 0) {
				this->totalRowCount = atoi(atts[i + 1]);
			}
		}
	}
	if (strcmp(name, "score") == 0) {
		const char *userName = nullptr;
		int level = 0;
		for (int i = 0; atts[i]; i += 2) {
			if (strcmp(atts[i], "userName") == 0) {
				userName = atts[i + 1];
			} else if (strcmp(atts[i], "level") == 0) {
				level = atoi(atts[i + 1]);
			}
		}
		this->scores.push_back(Score(userName, level));
	}
}

void JumpDownController::SAXDelegatorImpl::endElement(void *ctx, const char *name) {
}

void JumpDownController::SAXDelegatorImpl::textHandler(void *ctx, const char *s, int len) {
}

Page<Score> JumpDownController::SAXDelegatorImpl::buildPage() {
	return Page<Score>(this->pageIndex, this->pageSize, this->totalRowCount, this->scores);
}